﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TopDownShooter.Screens;
using Microsoft.Xna.Framework;
using FlatRedBall;
using Microsoft.Xna.Framework.Graphics;
using FlatRedBall.Math.Geometry;
using FlatRedBall.AI.Pathfinding;

namespace TopDownShooter
{
    enum State { Scout, Chase }
    enum MapSection { TopLeft, TopRight, BottomLeft, BottomRight }
    class Enemy : Unit
    {
        public static float MovementAllowance = .2f;
        internal bool NoClip = false;
        public Enemy(GameScreen screen)
            : base(screen)
        {
            Camera = new Camera(FlatRedBallServices.GlobalContentManager);
            Camera.AttachTo(this, false);
            Camera.RelativeZ = 100;
            Health = 100;
        }
        List<PositionedNode> nodePath;
        public void setPathTo(Vector3 pos)
        {
            nodePath = Screen.network.GetPath(
                ref Position,
                ref pos);
        }
        float noClipTime = .05f;
        float timeSinceNoclipStart = 0;

        public new void Activity()
        {
            if (NoClip)
            {
                timeSinceNoclipStart += TimeManager.SecondDifference;
                if (timeSinceNoclipStart >= noClipTime)
                {
                    timeSinceNoclipStart = 0;
                    NoClip = false;
                }
            }
            Vector2 movementVector = Vector2.Zero;
            // Do movement here //
            ChasePlayer();

            if (MoveTowardsTarget && nodePath != null && nodePath.Count != 0)
            {
                PositionedNode node = nodePath[0];
                float distance = (Position - node.Position).Length();
                if (distance < .6f)
                {
                    nodePath.RemoveAt(0);
                }
                else
                {
                    movementVector = AvoidTeammates(MoveToPoint(movementVector, node.Position));
                }
            }
                
            // Weapon selection // 
            float distanceToPlayer = (Screen.mainPlayer.Position - Position).Length();
            if (distanceToPlayer < 15)
                SelectWeapon(shotgun);
            else if (distanceToPlayer > 15 && distanceToPlayer < 40)
                SelectWeapon(smg);
            else
                SelectWeapon(pistol);

            if (!(movementVector.X == 0 && movementVector.Y == 0))
            {
                movementVector.Normalize();
                X += movementVector.X * speed;
                Y += movementVector.Y * speed;
            }
            foreach (Bullet b in bulletsFired)
                b.Activity();
            weapon.Activity();
            //Console.WriteLine(CurrentState); 
            if (collidedWithBox && MoveTowardsTarget && lastPos == Position && nodePath != null && nodePath.Count > 0)
            {
                // probably stuck
                setPathTo(nodePath[nodePath.Count - 1].Position);
            }
            lastPos = new Vector3(X, Y, Z);
            collidedWithBox = false;
            healthBar.SetHealth(Health);
            if (Health <= 0)
            {
                //Screen.SpawnEnemy();
                Game1.kills++;
                this.Destroy();
            }
        }

        private Vector2 AvoidTeammates(Vector2 movementVector)
        {
           /* for (int i = 0; i < Screen.enemies.Count; i++)
            {
                if (Screen.enemies[i] == this)
                    continue;
                Vector3 distanceVector = Screen.enemies[i].Position - Position;
                if (distanceVector.Length() < 4)
                {
                    movementVector.X -= distanceVector.X / 4;
                    movementVector.Y -= distanceVector.Y / 4;
                }
            }*/
            return movementVector;
        }
        Vector3 lastPos;
        private void AssignRandomMovementTarget()
        {
            SetTarget(Screen.network.Nodes[GameScreen.Random.Next(Screen.network.Nodes.Count)].Position);
        }
        bool collidedWithBox = false;
        internal void CollidedAgainstBox(Box blockage)
        {
            collidedWithBox = true;
        }

        private Box GetBoxInFront()
        {
            List<Box> possibles = new List<Box>();
            Line lineOfSight = new Line();
            lineOfSight.SetFromAbsoluteEndpoints(Position, Screen.mainPlayer.Position);
            for (int i = 0; i < Screen.boxes.Count; i++)
            {
                if (Screen.boxes[i].Rectangle.CollideAgainst(lineOfSight))
                    possibles.Add(Screen.boxes[i]);
            }
            if(possibles.Count == 0)
                return null;
            Box closest = possibles[0];
            float distance = Vector3.Distance(closest.Position, Position);
            for (int i = 1; i < possibles.Count; i++)
            {
                float compare = Vector3.Distance(possibles[i].Position, Position);
                if (compare < distance)
                {
                    distance = compare;
                    closest = possibles[i];
                }
            }
            return closest;
        }

        private void SetTarget(Vector3 vector3)
        {
            setPathTo(vector3);
        }

        Vector3 lastSeenPlayerAt;
        public bool AtTarget = true;
        public bool MoveTowardsTarget = true;

        private void ChasePlayer()
        {
            bool inView = ObjectInView(Screen.mainPlayer);
            bool inLineofSight = ClearLineOfSightTo(Screen.mainPlayer);
            //Console.WriteLine(inView + ", " + inLineofSight);
            if (!inView || !inLineofSight)
            {
                if (lastSeenPlayerAt == Position)
                    lastSeenPlayerAt = Screen.mainPlayer.Position;
                if (nodePath == null || nodePath.Count == 0)
                    SetTarget(lastSeenPlayerAt);
                if(nodePath.Count > 0 && (nodePath[nodePath.Count - 1].Position - Position).Length() < 0.3)
                    lastSeenPlayerAt = Screen.mainPlayer.Position;
                MoveTowardsTarget = true;
            }
            else
            {
                lastSeenPlayerAt = Screen.mainPlayer.Position;
                weapon.Fire();
                //MoveTowardsTarget = false;
            }
            
            PointAt(Screen.mainPlayer.Position);
        }

        private Vector2 MoveToPoint(Vector2 movementVector, Vector3 point)
        {
            if (point.X > X - MovementAllowance)
                movementVector.X++;
            if (point.X < X + MovementAllowance)
                movementVector.X--;
            if (point.Y > Y + MovementAllowance)
                movementVector.Y++;
            if (point.Y < Y - MovementAllowance)
                movementVector.Y--;
            return movementVector;
        }
        public bool ObjectInView(PositionedObject obj)
        {
            return (obj.Position - Position).Length() < 50;
            //return Camera.IsPointInView(obj.X, obj.Y, obj.Z);
        }

        internal void onBulletCollide(Bullet bullet)
        {
            Health -= bullet.Damage;
            bullet.Destroy();
        }
        int collisionTotal = 0;
        internal void CollidedAgainstEnemy(Enemy enemy)
        {
            collisionTotal++;
            if (collisionTotal > 5)
            {
                NoClip = true;
                collisionTotal = 0;
            }
        }
    }
}
